﻿using System.IO;
using System.Globalization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net;
using System.Net.NetworkInformation;
using GMap.NET.MapProviders;
using GMap.NET;
using GMap.NET.WindowsPresentation;
using GMap.NET.Projections;

using System.Collections.ObjectModel;
using RZD_maps.MapPath.Models;

namespace StaffLibrary
{
   
        public struct VehicleData
        {
            public int Id;
            public double Lat;
            public double Lng;
            public double Velocity;
            public string Line;
            public string LastStop;
            public string TrackType;
            public string AreaName;
            public string StreetName;
            public string Time;
            public double? Bearing;
        }

        public enum TransportType
        {
            Train,
            TrolleyBus,
        }

        public class Stuff
        {
#if !PocketPC
            public static bool PingNetwork(string hostNameOrAddress)
            {
                bool pingStatus = false;

                using (Ping p = new Ping())
                {
                    byte[] buffer = Encoding.ASCII.GetBytes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
                    int timeout = 4444; // 4s

                    try
                    {
                        PingReply reply = p.Send(hostNameOrAddress, timeout, buffer);
                        pingStatus = (reply.Status == IPStatus.Success);
                    }
                    catch (Exception)
                    {
                        pingStatus = false;
                    }
                }

                return pingStatus;
            }
#endif

            /// <summary>
            /// gets routes from gpsd log file
            /// </summary>
            /// <param name="gpsdLogFile"></param>
            /// <param name="start">start time(UTC) of route, null to read from very start</param>
            /// <param name="end">end time(UTC) of route, null to read to the very end</param>
            /// <param name="maxPositionDilutionOfPrecision">max value of PositionDilutionOfPrecision, null to get all</param>
            /// <returns></returns>
            public static IEnumerable<List<GpsLog>> GetRoutesFromMobileLog(string gpsdLogFile, DateTime? start, DateTime? end, double? maxPositionDilutionOfPrecision)
            {
#if SQLite
         using(SQLiteConnection cn = new SQLiteConnection())
         {
#if !MONO
            cn.ConnectionString = string.Format("Data Source=\"{0}\";FailIfMissing=True;", gpsdLogFile);
#else
            cn.ConnectionString = string.Format("Version=3,URI=file://{0},FailIfMissing=True", gpsdLogFile);
#endif

            cn.Open();
            {
               using(DbCommand cmd = cn.CreateCommand())
               {
                  cmd.CommandText = "SELECT * FROM GPS ";
                  int initLenght = cmd.CommandText.Length;

                  if(start.HasValue)
                  {
                     cmd.CommandText += "WHERE TimeUTC >= @t1 ";
                     SQLiteParameter lookupValue = new SQLiteParameter("@t1", start);
                     cmd.Parameters.Add(lookupValue);
                  }

                  if(end.HasValue)
                  {
                     if(cmd.CommandText.Length <= initLenght)
                     {
                        cmd.CommandText += "WHERE ";
                     }
                     else
                     {
                        cmd.CommandText += "AND ";
                     }

                     cmd.CommandText += "TimeUTC <= @t2 ";
                     SQLiteParameter lookupValue = new SQLiteParameter("@t2", end);
                     cmd.Parameters.Add(lookupValue);
                  }

                  if(maxPositionDilutionOfPrecision.HasValue)
                  {
                     if(cmd.CommandText.Length <= initLenght)
                     {
                        cmd.CommandText += "WHERE ";
                     }
                     else
                     {
                        cmd.CommandText += "AND ";
                     }

                     cmd.CommandText += "PositionDilutionOfPrecision <= @p3 ";
                     SQLiteParameter lookupValue = new SQLiteParameter("@p3", maxPositionDilutionOfPrecision);
                     cmd.Parameters.Add(lookupValue);
                  }

                  using(DbDataReader rd = cmd.ExecuteReader())
                  {
                     List<GpsLog> points = new List<GpsLog>();
                     while(rd.Read())
                     {
                        GpsLog log = new GpsLog();
                        {
                           log.TimeUTC = (DateTime)rd["TimeUTC"];
                           log.SessionCounter = (long)rd["SessionCounter"];
                           log.Delta = rd["Delta"] as double?;
                           log.Speed = rd["Speed"] as double?;
                           log.SeaLevelAltitude = rd["SeaLevelAltitude"] as double?;
                           log.EllipsoidAltitude = rd["EllipsoidAltitude"] as double?;
                           log.SatellitesInView = rd["SatellitesInView"] as System.Byte?;
                           log.SatelliteCount = rd["SatelliteCount"] as System.Byte?;
                           log.Position = new PointLatLng((double)rd["Lat"], (double)rd["Lng"]);
                           log.PositionDilutionOfPrecision = rd["PositionDilutionOfPrecision"] as double?;
                           log.HorizontalDilutionOfPrecision = rd["HorizontalDilutionOfPrecision"] as double?;
                           log.VerticalDilutionOfPrecision = rd["VerticalDilutionOfPrecision"] as double?;
                           log.FixQuality = (FixQuality)((byte)rd["FixQuality"]);
                           log.FixType = (FixType)((byte)rd["FixType"]);
                           log.FixSelection = (FixSelection)((byte)rd["FixSelection"]);
                        }

                        if(log.SessionCounter == 0 && points.Count > 0)
                        {
                           List<GpsLog> ret = new List<GpsLog>(points);
                           points.Clear();
                           {
                              yield return ret;
                           }
                        }

                        points.Add(log);
                     }

                     if(points.Count > 0)
                     {
                        List<GpsLog> ret = new List<GpsLog>(points);
                        points.Clear();
                        {
                           yield return ret;
                        }
                     }

                     points.Clear();
                     points = null;

                     rd.Close();
                  }
               }
            }
            cn.Close();
         }
#else
                return null;
#endif
            }

            static readonly Random r = new Random();

            /// <summary>
            /// gets realtime data from public transport in city vilnius of lithuania
            /// </summary>
            /// <param name="type">type of transport</param>
            /// <param name="line">linenum or null to get all</param>
            /// <param name="ret"></param>
            public static void GetVilniusTransportData(TransportType type, string line, List<VehicleData> ret)
            {
                ret.Clear();

                //http://stops.lt/vilnius/gps.txt?1318577178193
                //http://www.marsrutai.lt/vilnius/Vehicle_Map.aspx?trackID=34006&t=1318577231295
                // http://www.troleibusai.lt/eismas/get_gps.php?allowed=true&more=1&bus=1&rand=0.5487859781558404

                string url = string.Format(CultureInfo.InvariantCulture, "http://www.troleibusai.lt/eismas/get_gps.php?allowed=true&more=1&bus={0}&rand={1}", type == TransportType.Train ? 2 : 1, r.NextDouble());

                if (!string.IsNullOrEmpty(line))
                {
                    url += "&nr=" + line;
                }

#if !PocketPC
                url += "&app=GMap.NET.Desktop";
#else
         url += "&app=GMap.NET.WindowsMobile";
#endif

                string xml = string.Empty;
                {
                    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);

                    request.UserAgent = GMapProvider.UserAgent;
                    request.Timeout = GMapProvider.TimeoutMs;
                    request.ReadWriteTimeout = GMapProvider.TimeoutMs * 6;
                    request.Accept = "*/*";
                    request.KeepAlive = true;

                    using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                    {
                        using (Stream responseStream = response.GetResponseStream())
                        {
                            using (StreamReader read = new StreamReader(responseStream, Encoding.UTF8))
                            {
                                xml = read.ReadToEnd();
                            }
                        }
#if PocketPC
               request.Abort();
#endif
                        response.Close();
                    }
                }

                // 54.690688; 25.2116; 1263522; 1; 48.152; 2011-10-14 14:41:29

                if (!string.IsNullOrEmpty(xml))
                {
                    var items = xml.Split('&');

                    foreach (var it in items)
                    {
                        var sit = it.Split(';');
                        if (sit.Length == 8)
                        {
                            VehicleData d = new VehicleData();
                            {
                                d.Id = int.Parse(sit[2]);
                                d.Lat = double.Parse(sit[0], CultureInfo.InvariantCulture);
                                d.Lng = double.Parse(sit[1], CultureInfo.InvariantCulture);
                                d.Line = sit[3];
                                if (!string.IsNullOrEmpty(sit[4]))
                                {
                                    d.Bearing = double.Parse(sit[4], CultureInfo.InvariantCulture);
                                }

                                if (!string.IsNullOrEmpty(sit[5]))
                                {
                                    d.Time = sit[5];

                                    var t = DateTime.Parse(d.Time);
                                    if (DateTime.Now - t > TimeSpan.FromMinutes(5))
                                    {
                                        continue;
                                    }

                                    d.Time = t.ToLongTimeString();
                                }

                                d.TrackType = sit[6];
                            }

                            //if(d.Id == 1262760)
                            //if(d.Line == "13")
                            {
                                ret.Add(d);
                            }
                        }
                    }
                }
                #region -- old --
                //XmlDocument doc = new XmlDocument();
                //{
                //   doc.LoadXml(xml);

                //   XmlNodeList devices = doc.GetElementsByTagName("Device");
                //   foreach(XmlNode dev in devices)
                //   {
                //      VehicleData d = new VehicleData();
                //      d.Id = int.Parse(dev.Attributes["ID"].InnerText);

                //      foreach(XmlElement elem in dev.ChildNodes)
                //      {
                //         // Debug.WriteLine(d.Id + "->" + elem.Name + ": " + elem.InnerText);

                //         switch(elem.Name)
                //         {
                //            case "Lat":
                //            {
                //               d.Lat = double.Parse(elem.InnerText, CultureInfo.InvariantCulture);
                //            }
                //            break;

                //            case "Lng":
                //            {
                //               d.Lng = double.Parse(elem.InnerText, CultureInfo.InvariantCulture);
                //            }
                //            break;

                //            case "Bearing":
                //            {
                //               if(!string.IsNullOrEmpty(elem.InnerText))
                //               {
                //                  d.Bearing = double.Parse(elem.InnerText, CultureInfo.InvariantCulture);
                //               }
                //            }
                //            break;

                //            case "LineNum":
                //            {
                //               d.Line = elem.InnerText;
                //            }
                //            break;

                //            case "AreaName":
                //            {
                //               d.AreaName = elem.InnerText;
                //            }
                //            break;

                //            case "StreetName":
                //            {
                //               d.StreetName = elem.InnerText;
                //            }
                //            break;

                //            case "TrackType":
                //            {
                //               d.TrackType = elem.InnerText;
                //            }
                //            break;

                //            case "LastStop":
                //            {
                //               d.LastStop = elem.InnerText;
                //            }
                //            break;

                //            case "Time":
                //            {
                //               d.Time = elem.InnerText;
                //            }
                //            break;
                //         }
                //      }
                //      ret.Add(d);
                //   }
                //} 
                #endregion
            }

            public static string sessionId = string.Empty;
            public static double Lat = 55.742059;
            public static double Lng = 38.970662;
            public static bool bFirst = true;
            public static bool bDirection = true;

            public static double time=0;

            private struct pathdata
            {
                public double time;
                public double difftm;
                public PointLatLng ptStart;
                public PointLatLng ptStop;
                public double dtLng;
                public double dtLat;
                public double velocity;
            }

            private static List<List<pathdata>> pdata = new List<List<pathdata>>();

            public static void InitDataFromXML()
            {
                Model data = new Model();
                double tm = 0;
                pathdata dt;
                bool bFirst;
                foreach(var route in data.Categories)
                {
                    tm = 0;
                    PointLatLng pt1;
                    PointLatLng pt2;
                    bFirst = true;
                    List<pathdata> rtinfo = new List<pathdata>();
                    
                    double distance;
                    pt1 = new PointLatLng();
                    pt2 = new PointLatLng();

                    double dlat, dlng, clat, clng, clat1, clng1;
                    int _cnt;

                    foreach (var point in route.SubCategories)
                    {
                        if (bFirst)
                        {
                            pt1 = new PointLatLng(point.Lat, point.Lng);
                            pt2 = pt1;
                            bFirst = false;
                            continue;
                        }

                        pt1 = pt2;
                        pt2 = new PointLatLng(point.Lat, point.Lng);

                        // интерполяция - добавление 50 промежуточных точек
                        dlat = (pt2.Lat - pt1.Lat) / 50;
                        dlng = (pt2.Lng - pt1.Lng) / 50;
                        for (_cnt = 0; _cnt < 50; _cnt++)
                        {
                            clat1 = pt1.Lat;
                            clng1 = pt1.Lng;
                            clat = pt1.Lat + dlat*_cnt;
                            clng = pt1.Lng + dlng * _cnt;
                            distance = MercatorProjection.Instance.GetDistance(new PointLatLng(clat1, clng1), new PointLatLng(clat, clng));
                            dt = new pathdata();
                            dt.ptStart = new PointLatLng(clat1, clng1);
                            dt.ptStop = new PointLatLng(clat, clng);
                            dt.velocity = point.Velocity;
                            dt.time = tm;
                            tm += distance / dt.velocity;
                            dt.difftm = tm - dt.time;
                            dt.dtLng = dlng;
                            dt.dtLat = dlat;
                            rtinfo.Add(dt);

                        }
                        // конец интерполяции

                        ////distance = GMapProviders.OpenStreetMap.Projection.GetDistance(pt2, pt1);
                        //distance = MercatorProjection.Instance.GetDistance(pt2, pt1);
                        
                        //dt = new pathdata();
                        //dt.ptStart = pt1;
                        //dt.ptStop = pt2;
                        //dt.velocity = point.Velocity;
                        //dt.time = tm;
                        //tm += distance / dt.velocity;
                        //dt.difftm = tm - dt.time;
                        //dt.dtLng = (pt2.Lng - pt1.Lng);
                        //dt.dtLat = (pt2.Lat - pt1.Lat);
                        //rtinfo.Add(dt);
                    }

                    //List<pathdata> rtinfomirror = new List<pathdata>();
                    //int _cnt;
                    //for (_cnt = 0; _cnt < rtinfo.Count; _cnt++)
                    //{
                    //    dt = new pathdata();
                    //    pathdata oldItem = rtinfo.ElementAt(rtinfo.Count - _cnt - 1);
                    //    dt.ptStart = oldItem.ptStop;
                    //    dt.velocity = oldItem.velocity;
                    //    dt.difftm = oldItem.difftm;
                    //    dt.time = tm;
                    //    tm += oldItem.difftm;
                    //    dt.dtLat = -oldItem.dtLat;
                    //    dt.dtLng = -oldItem.dtLng;
                    //    rtinfomirror.Add(dt);
                    //}
                    //rtinfo.AddRange(rtinfomirror);

                    pdata.Add(rtinfo);
                }
            }

            public static void GetTransportDataXML(TransportType type, string line, List<VehicleData> ret)
            {
                pathdata prevdata, curdata;
                VehicleData data = new VehicleData();
                int id=0;
                foreach (var item in pdata)
                {
                    double last_time = item.ElementAt(item.Count - 1).time;
                    double cur_time = time - Math.Floor(time / last_time) * last_time;
                    bool bFirst=true;
                    curdata = new pathdata();
                    prevdata = new pathdata();
                    foreach (var it in item)
                    {
                        if (bFirst)
                        {
                            prevdata = it;
                            curdata = it;
                            bFirst = false;
                            if (curdata.time > cur_time) break;
                            continue;
                        }
                        prevdata = curdata;
                        curdata = it;
                        if (curdata.time > cur_time) break;
                    }
                    if (false == bFirst)
                    {
                        // найден хотя бы один элемент маршрута
                        double calc_time = curdata.time - cur_time;// - cur_time +prevdata.time;
                        double lat = prevdata.ptStart.Lat; 
                        double lng = prevdata.ptStart.Lng;
                        if (prevdata.time != curdata.time)
                        {
                            lat = lat;// +calc_time / (curdata.time - prevdata.time) * prevdata.dtLat;
                            lng = lng;// +calc_time / (curdata.time - prevdata.time) * prevdata.dtLng;
                        }
                        else
                        {
                            lat = lat;// +calc_time / curdata.time * prevdata.dtLat;
                            lng = lng;// +calc_time / curdata.time * prevdata.dtLng;
                        }
                        data.Id = id + 1;
                        data.Lat = lat;
                        data.Lng = lng;
                        data.Velocity = prevdata.velocity;
                        data.Line = string.Format("Маршрут {0}",id+1);
                        ret.Add(data);
                    }
                    id++;
                }
                time = time + 0.03;
            }

            public static void GetTransportData(TransportType type, string line, List<VehicleData> ret)
            {
                
                ret.Clear();
                VehicleData d = new VehicleData();
                d.Id = 1;
                if (bFirst == true)
                {
                    d.Lat = Lat;
                    d.Lng = Lng;
                    bFirst = false;
                }
                else
                {
                    d.Lat = Lat;
                    d.Lng = Lng;
                    if (bDirection)
                        d.Lat += 0.001;
                    else
                        d.Lat -= 0.001;
                    Lat = d.Lat;
                    Lng = d.Lng;
                    if (d.Lat > 56.1 || d.Lat < 54.9)
                        bDirection = !bDirection;

                }
                d.Line = "Линия";
                d.Time = "11:45";
                d.TrackType = "Тип пути";
                ret.Add(d);
            }
        }
    }

